import java.util.ListIterator;


public class MultipleChain extends Chain{

	private int succNum;
	//backupDistance is interval after every node that has to contain succNum successors
	private double backupDistance;
	
	public MultipleChain(double bTotal, long tMax, double lambda, double mu,
			int nodesNum, int succNum) throws Exception {
		super(bTotal, tMax, lambda, mu, nodesNum);
		
		this.succNum = succNum; 
		if(succNum >= nodesNum) throw new Exception("Succ >= nodes num");
		backupDistance = ((double)bTotal*succNum)/nodesNum; 
	}


	@Override
	public double makeNodesShift(double maxDistanceToRun) {
		//calculate srcMove by distance to the last bad node and maxDistanceToRun
		if(badNodes.isEmpty()) return maxDistanceToRun;
		
		Node lastBad = badNodes.getLast();
		double srcMove = Math.min(maxDistanceToRun, bTotal - lastBad.relIdx);
		//move all bad nodes right for the distance of srcMove, update their relative position
		for(Node n:badNodes) {
			n.relIdx += srcMove;
		}
		//update indexes of bad nodes in the array
		updateBadNodesIdx();
		//traverse good nodes from right to left, move every good node right if it could not move for srcMove
		updateGoodNodesPosition();
		return srcMove;
	}


	private void updateGoodNodesPosition() {
		int last = allNodes.length -1;
		int first = last - succNum;
		
		while(first > 0) {
			double lastRel = allNodes[last].relIdx;
			for(int i = first; i < last; ++i) {
				Node n = allNodes[i];
				if(n.state == State.Bad) continue;
				
				double distance = lastRel - n.relIdx; 
				if(distance <= backupDistance) break;

				n.relIdx = lastRel - backupDistance;
			}
			first--;
			last--;
		}
	}

	/**
	 * Shift bad nodes s.t. the array will be sorted according to relId position of the nodes
	 */
	private void updateBadNodesIdx() {

		ListIterator<Node> iter = badNodes.listIterator(badNodes.size());
		
		while(iter.hasPrevious()) {
			Node n = iter.previous();
			int idx = n.id;
			while(idx < allNodes.length -1 && allNodes[idx+1].relIdx < n.relIdx) {
				swapNodes(idx,idx+1);
			}
		}
		
	}

	private void swapNodes(int i1, int i2) {
		Node n1 = allNodes[i1];
		Node n2 = allNodes[i2];
		
		n1.id = i2;
		n2.id = i1;
		
		allNodes[i1] = n2;
		allNodes[i2] = n1;
	}

}
